using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Practices.CompositeUI.SmartParts;
using NUnit.Framework;
using SCSFContrib.CompositeUI.WPF.Workspaces;

namespace SCSFContrib.CompositeUI.WPF.UnitTest.Workspaces
{
	[TestFixture]
	public sealed class WindowWorkspaceTest : UnitTest
	{
		private WindowWorkspace _windowWorkspace;

		protected override void SetUpCore()
		{
			base.SetUpCore();
			_windowWorkspace = new WindowWorkspace();
		}

		[Test]
		public void OnApplySmartPartInfo_ShouldApplyInfoToRelatedWindow()
		{
			string smartPart = "abc";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			_windowWorkspace.Show(smartPart, smartPartInfo);
			Window window = _windowWorkspace.Windows[smartPart];

			smartPartInfo.SizeToContent = SizeToContent.WidthAndHeight;

			Assert.AreEqual(SizeToContent.Manual, window.SizeToContent);
			_windowWorkspace.ApplySmartPartInfo(smartPart, smartPartInfo);
			Assert.AreEqual(SizeToContent.WidthAndHeight, window.SizeToContent);
		}

		[Test]
		public void OnShow_ShouldShowSmartPartInWindow()
		{
			string smartPart = "abc";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			Assert.IsEmpty(_windowWorkspace.Windows.Keys as System.Collections.ICollection);
			_windowWorkspace.Show(smartPart, smartPartInfo);
			Assert.IsNotEmpty(_windowWorkspace.Windows.Keys as System.Collections.ICollection);
			Assert.IsTrue(_windowWorkspace.Windows.ContainsKey(smartPart));
			Window window = _windowWorkspace.Windows[smartPart];
			Assert.AreEqual(smartPart, window.Content);
		}

		[Test]
		public void OnShow_ShouldShowWindowModallyIfRequested()
		{
			ExecuteInSeparateAppDomain("OnShow_ShouldShowWindowModallyIfRequested_DoWork");
		}

		private void OnShow_ShouldShowWindowModallyIfRequested_DoWork()
		{
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();
			ManualResetEvent windowShown = new ManualResetEvent(false);
			ManualResetEvent windowClosed = new ManualResetEvent(false);
			smartPartInfo.IsModal = true;
			UserControl smartPart = null;
			SynchronizationContext synchronizationContext = null;

			//start up window on a separate thread
			Thread thread = CreateSTAThread(delegate
			{
				smartPart = new UserControl();

				smartPart.Loaded += delegate
				{
					synchronizationContext = SynchronizationContext.Current;
					windowShown.Set();
				};

				_windowWorkspace.Show(smartPart, smartPartInfo);
				windowClosed.Set();
			});

			thread.Start();
			windowShown.WaitOne();
			Window window = _windowWorkspace.Windows[smartPart];

			if (windowClosed.WaitOne(1000, true))
			{
				Assert.Fail("Wasn't expecting window to be closed.");
			}

			synchronizationContext.Send(delegate
			{
				window.Close();
			}, null);
		}

		[Test]
		public void OnShow_ShouldSetDialogResult()
		{
			ExecuteInSeparateAppDomain("OnShow_ShouldSetDialogResult_DoWork");
		}

		private void OnShow_ShouldSetDialogResult_DoWork()
		{
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();
			ManualResetEvent windowShown = new ManualResetEvent(false);
			ManualResetEvent windowClosed = new ManualResetEvent(false);
			smartPartInfo.IsModal = true;
			UserControl smartPart = null;
			SynchronizationContext synchronizationContext = null;
			Assert.IsNull(smartPartInfo.DialogResult);

			//start up window on a separate thread
			Thread thread = CreateSTAThread(delegate
			{
				smartPart = new UserControl();

				smartPart.Loaded += delegate
				{
					synchronizationContext = SynchronizationContext.Current;
					windowShown.Set();
				};

				_windowWorkspace.Show(smartPart, smartPartInfo);
				windowClosed.Set();
			});

			thread.Start();
			windowShown.WaitOne();
			Window window = _windowWorkspace.Windows[smartPart];

			if (windowClosed.WaitOne(1000, true))
			{
				Assert.Fail("Wasn't expecting window to be closed.");
			}

			synchronizationContext.Send(delegate
			{
				window.DialogResult = true;
				window.Close();
			}, null);

			windowClosed.WaitOne();
			Assert.IsTrue(smartPartInfo.DialogResult.Value);
		}

		[Test]
		public void OnActivate_ShouldActivateRelatedWindow()
		{
			ExecuteInSeparateAppDomain("OnActivate_ShouldActivateRelatedWindow_DoWork");
		}

		private void OnActivate_ShouldActivateRelatedWindow_DoWork()
		{
			string smartPart1 = "abc";
			string smartPart2 = "def";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			_windowWorkspace.Show(smartPart1, smartPartInfo);
			Window window1 = _windowWorkspace.Windows[smartPart1];
			Assert.IsTrue(window1.IsActive);

			_windowWorkspace.Show(smartPart2, smartPartInfo);
			Window window2 = _windowWorkspace.Windows[smartPart2];
			Assert.IsTrue(window2.IsActive);

			Assert.IsFalse(window1.IsActive);
			_windowWorkspace.Activate(smartPart1);
			Assert.IsTrue(window1.IsActive);

			Assert.IsFalse(window2.IsActive);
			_windowWorkspace.Activate(smartPart2);
			Assert.IsTrue(window2.IsActive);
		}

		[Test]
		public void OnHide_ShouldHideRelatedWindow()
		{
			ExecuteInSeparateAppDomain("OnHide_ShouldHideRelatedWindow_DoWork");
		}
	
		private void OnHide_ShouldHideRelatedWindow_DoWork()
		{
			string smartPart = "abc";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			_windowWorkspace.Show(smartPart, smartPartInfo);
			Window window = _windowWorkspace.Windows[smartPart];

			Assert.IsTrue(window.IsVisible);
			_windowWorkspace.Hide(smartPart);
			Assert.IsFalse(window.IsVisible);
		}

		[Test]
		public void OnClose_ShouldCloseRelatedWindow()
		{
			ExecuteInSeparateAppDomain("OnClose_ShouldCloseRelatedWindow_DoWork");
		}

		private void OnClose_ShouldCloseRelatedWindow_DoWork()
		{
			string smartPart = "abc";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			_windowWorkspace.Show(smartPart, smartPartInfo);
			Window window = _windowWorkspace.Windows[smartPart];

			Assert.IsTrue(window.IsVisible);
			Assert.IsTrue(_windowWorkspace.Windows.ContainsKey(smartPart));
			_windowWorkspace.Close(smartPart);
			Assert.IsFalse(window.IsVisible);
			Assert.IsFalse(_windowWorkspace.Windows.ContainsKey(smartPart));
		}

		[Test]
		public void OnClose_ShouldDisconnectSmartPartFromWindow()
		{
			ExecuteInSeparateAppDomain("OnClose_ShouldDisconnectSmartPartFromWindow_DoWork");
		}

		private void OnClose_ShouldDisconnectSmartPartFromWindow_DoWork()
		{
			string smartPart = "abc";
			WindowSmartPartInfo smartPartInfo = GetSmartPartInfo();

			_windowWorkspace.Show(smartPart, smartPartInfo);
			Window window = _windowWorkspace.Windows[smartPart];

			Assert.AreSame(smartPart, window.Content);
			_windowWorkspace.Close(smartPart);
			Assert.IsNull(window.Content);

			_windowWorkspace.Show(smartPart, smartPartInfo);
			window = _windowWorkspace.Windows[smartPart];

			Assert.AreSame(smartPart, window.Content);
			window.Close();
			Assert.IsNull(window.Content);
		}

		[Test]
		public void ConvertFrom_ShouldOnlyCopyBaseInformationIfSourceIsntWindowSmartPartInfo()
		{
			SmartPartInfo source = new SmartPartInfo();
			source.Title = "title";
			source.Description = "desc";

			WindowSmartPartInfo windowSmartPartInfo = InvokePrivateMethod<WindowSmartPartInfo>(_windowWorkspace, "ConvertFrom", source);
			Assert.AreEqual("title", windowSmartPartInfo.Title);
			Assert.AreEqual("desc", windowSmartPartInfo.Description);
		}

		[Test]
		public void ConvertFrom_ShouldCopyWindowPropertiesIfSourceIsWindowSmartPartInfo()
		{
			ImageSource icon = new DrawingImage();
			Style style = new Style();
			Window owner = new Window();
			WindowSmartPartInfo source = new WindowSmartPartInfo();
			source.Title = "title";
			source.Description = "desc";
			source.IsModal = true;
			source.Width = 200;
			source.Height = 300;
			source.MinWidth = 50;
			source.MinHeight = 40;
			source.MaxWidth = 400;
			source.MaxHeight = 350;
			source.Left = 45;
			source.Top = 55;
			source.ShowInTaskbar = false;
			source.IsTopmost = true;
			source.Icon = icon;
			source.ResizeMode = ResizeMode.CanResizeWithGrip;
			source.SizeToContent = SizeToContent.Height;
			source.StartupLocation = WindowStartupLocation.CenterOwner;
			source.State = WindowState.Maximized;
			source.Style = WindowStyle.None;
			source.WpfStyle = style;
			source.Owner = owner;

			WindowSmartPartInfo windowSmartPartInfo = InvokePrivateMethod<WindowSmartPartInfo>(_windowWorkspace, "ConvertFrom", source);
			Assert.AreEqual("title", windowSmartPartInfo.Title);
			Assert.AreEqual("desc", windowSmartPartInfo.Description);
			Assert.IsTrue(windowSmartPartInfo.IsModal);
			Assert.AreEqual(200, windowSmartPartInfo.Width);
			Assert.AreEqual(300, windowSmartPartInfo.Height);
			Assert.AreEqual(50D, windowSmartPartInfo.MinWidth);
			Assert.AreEqual(40D, windowSmartPartInfo.MinHeight);
			Assert.AreEqual(400D, windowSmartPartInfo.MaxWidth);
			Assert.AreEqual(350D, windowSmartPartInfo.MaxHeight);
			Assert.AreEqual(45D, windowSmartPartInfo.Left);
			Assert.AreEqual(55D, windowSmartPartInfo.Top);
			Assert.IsFalse(windowSmartPartInfo.ShowInTaskbar.Value);
			Assert.IsTrue(windowSmartPartInfo.IsTopmost.Value);
			Assert.AreSame(icon, windowSmartPartInfo.Icon);
			Assert.AreEqual(ResizeMode.CanResizeWithGrip, windowSmartPartInfo.ResizeMode);
			Assert.AreEqual(SizeToContent.Height, windowSmartPartInfo.SizeToContent);
			Assert.AreEqual(WindowStartupLocation.CenterOwner, windowSmartPartInfo.StartupLocation);
			Assert.AreEqual(WindowState.Maximized, windowSmartPartInfo.State);
			Assert.AreEqual(WindowStyle.None, windowSmartPartInfo.Style);
			Assert.AreSame(style, windowSmartPartInfo.WpfStyle);
			Assert.AreSame(owner, windowSmartPartInfo.Owner);
		}

		#region Supporting Methods

		private WindowSmartPartInfo GetSmartPartInfo()
		{
			WindowSmartPartInfo smartPartInfo = new WindowSmartPartInfo();
			smartPartInfo.Width = 0;
			smartPartInfo.Height = 0;
			smartPartInfo.ShowInTaskbar = false;
			smartPartInfo.Style = WindowStyle.None;
			return smartPartInfo;
		}

		#endregion
	}
}